from crawler_core.constant.constants import Constants
from crawler_core.constant.constants_account import ConstantAccount
from crawler_core.constant.constants_api import ConstantAPI
from crawler_core.event.task_impl.task_login_down import TaskLoginDown
from crawler_core.utils.redis_utils import RedisUtils
from lib.sys.logger_factory import LoggerFactory


class TaskLogin(object):
    logger = LoggerFactory.getLogger("TaskLogin", "login")

    def __init__(self):
        pass

    def start(self):
        # 获取任务Id
        task_id = RedisUtils.getLoginTask()
        if task_id:
            # 获取任务--执行对象
            TaskLogin.logger.info("获取登录任务 -- [%s] --" % task_id)
            context = RedisUtils.getEventTask(task_id)
        else:
            return
        if not context:
            return
        event_type = context[Constants.CONTEXT_EVENT_TYPE]
        TaskLogin.logger.info("登录任务 -- [%s] --获取任务类型，--[%s]-- ..." % (task_id, event_type))
        # 判断cookies 是否存在
        cookies = RedisUtils.getCookies(context[Constants.CONTEXT_TYPE], context[Constants.CONTEXT_CORP_CODE],
                                        context[Constants.CONTEXT_USERNAME])
        if cookies:
            TaskLogin.logger.info("登录任务 -- [%s] -- cookies 存在，开始任务--[%s]-- ..." % (task_id, event_type))
            if event_type == Constants.EVENT_TYPE_DOWNLOAD:
                RedisUtils.setDownloadTask(task_id)
            elif event_type == Constants.EVENT_TYPE_SEARCH:
                RedisUtils.setSearchTask(task_id)
        else:
            # 首先先登录账号，然后处理任务调度
            # 1、账号登录，处理多账号登录，获取cookies
            c_data = TaskLoginDown.do_login(task_id, context)
            # 刷新当前context 保存到消息中心
            RedisUtils.refreshEventTask(task_id, context)
            # 2、处理任务调度
            if c_data.get(ConstantAccount.LOGIN_STATUS) == ConstantAccount.LOGIN_STATUS_NO_ACCOUNT:
                if event_type == Constants.EVENT_TYPE_DOWNLOAD:
                    content = {
                        Constants.LOGIN_CODE: ConstantAPI.RETURN_ERROR_ACCOUNT,
                        Constants.LOGIN_MSG: ConstantAPI.RETURN_ERROR_ACCOUNT_MSG
                    }
                    TaskLogin.logger.info("登录任务 -- [%s] --下载登录, 无可用下载账号，退出下载 ..." % task_id)
                    # 下载任务结束 直接发送 API 返回命令
                    RedisUtils.setApiDownloadReturn(task_id, content)
                    RedisUtils.setDownloadTask(task_id)
                return
            elif c_data.get(ConstantAccount.LOGIN_STATUS) == ConstantAccount.LOGIN_STATUS_EXCEPTION:
                TaskLogin.logger.info("登录任务 -- [%s] --登录失败, 异常错误信息，任务结束 ..." % task_id)
                json_data = RedisUtils.getEventTask(task_id)
                if event_type == Constants.EVENT_TYPE_DOWNLOAD:
                    tenant_id = json_data[Constants.API_PARAM_TENANT_ID]
                    # @TODO 异常错误 需要回收 --记录主任务 channelType, account 加锁, 阻止 下载任务 再次分配
                    # 删除当前任务
                    RedisUtils.delEventTask(task_id)
                    # 下载过滤重复数据，加锁后，需要解锁
                    RedisUtils.removeEventDownloadLock(tenant_id)
                elif event_type == Constants.EVENT_TYPE_SEARCH:
                    root_task_id = json_data[Constants.CONTEXT_ROOT_TASK_ID]
                    # @TODO 异常错误 需要回收 --记录主任务 channelType, account 加锁, 阻止 查询主任务 再次分配
                    TaskLogin.logger.info("登录任务 -- [%s] --登录失败, 查询任务结束，任务结束 ..." % task_id)
                    # 删除当前任务
                    RedisUtils.delEventTask(task_id)
                    # 更新主任务状态 is_over = 1 任务完成
                    RedisUtils.refreshEventSearchContextIsOver(root_task_id, 1)
                return
            else:
                # 获取cookies, 需要判断cookies
                cookies = c_data.get(ConstantAccount.COOKIES)
                _type = context[Constants.CONTEXT_TYPE]
                # corp_code = context[Constants.CONTEXT_CORP_CODE]
                # username = context[Constants.CONTEXT_USERNAME]
                # 存放cookies
                if cookies:
                    RedisUtils.setCookies(context[Constants.CONTEXT_TYPE], context[Constants.CONTEXT_CORP_CODE],
                                          context[Constants.CONTEXT_USERNAME], cookies)

                if event_type == Constants.EVENT_TYPE_DOWNLOAD:
                    # 生成下载锁定任务，防止查询登出
                    # RedisUtils.setLoginDtemp(context[Constants.CONTEXT_TYPE], context[Constants.CONTEXT_CORP_CODE],
                    #                      context[Constants.CONTEXT_USERNAME])

                    TaskLogin.logger.info("登录任务 -- [%s] --下载登录, 登录成功，发送下载任务 ..." % task_id)
                    RedisUtils.setDownloadTask(task_id)

                elif event_type == Constants.EVENT_TYPE_SEARCH:
                    # is_true = RedisUtils.isExistLoginDtemp(_type, corp_code, username)
                    TaskLogin.logger.info("登录任务 -- [%s] --查询登录, Cookie已存在，发送查询任务 ..." % task_id)
                    RedisUtils.setSearchTask(task_id)

# def do_login(self, task_id, context):
# 	_type = context[Constants.CONTEXT_TYPE]
# 	corp_code = context[Constants.CONTEXT_CORP_CODE]
# 	username = context[Constants.CONTEXT_USERNAME]
# 	# 当前任务，某个渠道，存在的所有账号 list_account
# 	list_account = context[Constants.CONTEXT_ACCOUNT_LIST]
# 	a_size = len(list_account)
# 	# obj = RedisUtils.getEventAccount(corp_code, _type)，获取当前企业，某个渠道所有账号，状态是否可用的存储对象
# 	# 对象状态分为（账号密码错误=0，可登录=1，点数不够=2）
# 	obj = RedisUtils.getEventAccount(corp_code, _type)
# 	# 初始化-默认状态
# 	status = ConstantAccount.STATUS_DEFAULT
# 	if obj:
# 		# 从对象中，获取username的存储状态
# 		status = obj.get(username)
# 	# 开始判断状态
# 	# 1、当前状态，账号错误，需要登录可用账号
# 	if status == ConstantAccount.STATUS_ACCOUNT_ERROR:
# 		# a_size 表示 当前企业账号只有一个
# 		if a_size == 1:
# 			# 当前企业账号只有一个且错误账号，直接结束任务
# 			return {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_ERROR,
# 					ConstantAccount.LOGIN_STATUS: ConstantAccount.LOGIN_STATUS_NO_ACCOUNT}
# 		else:
# 			# 如果 obj 存在表示已登录验证过，因此，获取对象所有账户数组 keys = obj.keys()，比较当前任务账户集合list_account大小，
# 			# len(keys) == a_size，表示，当前账号是最后一个循环登录账号，无可用账号，直接结束任务
# 			if obj:
# 				keys = obj.keys()
# 				if len(keys) == a_size:
# 					# 无账号可用，直接结束任务
# 					return {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_ERROR,
# 							ConstantAccount.LOGIN_STATUS: ConstantAccount.LOGIN_STATUS_NO_ACCOUNT}
# 				else:
# 					# 存在可用账号，直接登录下一个账号
# 					return self.login_channel_next(task_id, context, corp_code, _type, username)
# 			# 如果 obj 不存在，表示没有任何账号登录且验证过，需要使用当前账号登录并完成验证
# 			else:
# 				# 先登录当前账号
# 				l_data = self.login_channel(task_id, context)
# 				# 判断登录结果，
# 				if l_data.get(ConstantAccount.STATUS) == ConstantAccount.STATUS_ACCOUNT_ERROR:
# 					# l_data.get(ConstantAccount.STATUS)登录失败，先标记当前账号有问题，然后继续执行登录(下一个账号)
# 					RedisUtils.addEventAccount(corp_code, _type, username, ConstantAccount.STATUS_ACCOUNT_ERROR)
# 					return self.do_login(task_id, context)
# 				elif l_data.get(ConstantAccount.STATUS) == ConstantAccount.STATUS_ACCOUNT_OK:
# 					# 登录成功，直接返回
# 					RedisUtils.addEventAccount(corp_code, _type, username, ConstantAccount.STATUS_ACCOUNT_OK)
# 					l_data[ConstantAccount.LOGIN_STATUS] = ConstantAccount.LOGIN_STATUS_SUCCESS
# 					return l_data
# 				else:
# 					# 异常--登录失败，直接返回
# 					return {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_ERROR,
# 							ConstantAccount.LOGIN_STATUS: ConstantAccount.LOGIN_STATUS_EXCEPTION}
# 	else:
# 		if status == ConstantAccount.STATUS_DEFAULT or status == ConstantAccount.STATUS_COOKIES_LOSE:
# 			# 2、当前账号没有记录有效性(新开始的任务),或者cookies失效， 开始执行登录
# 			l_data = self.login_channel(task_id, context)
# 			# 判断登录结果，
# 			if l_data.get(ConstantAccount.STATUS) == ConstantAccount.STATUS_ACCOUNT_ERROR:
# 				# l_data.get(ConstantAccount.STATUS_ACCOUNT_ERROR)登录失败，先标记当前账号有问题，然后继续执行登录(下一个账号)
# 				RedisUtils.addEventAccount(corp_code, _type, username, ConstantAccount.STATUS_ACCOUNT_ERROR)
# 				return self.do_login(task_id, context)
# 			elif l_data.get(ConstantAccount.STATUS) == ConstantAccount.STATUS_ACCOUNT_OK:
# 				# 登录成功，直接返回
# 				RedisUtils.addEventAccount(corp_code, _type, username, ConstantAccount.STATUS_ACCOUNT_OK)
# 				l_data[ConstantAccount.LOGIN_STATUS] = ConstantAccount.LOGIN_STATUS_SUCCESS
# 				return l_data
# 			else:
# 				# 异常--登录失败，直接返回
# 				return {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_ERROR,
# 						ConstantAccount.LOGIN_STATUS: ConstantAccount.LOGIN_STATUS_EXCEPTION}
# 		else:
# 			# 3、存在可用 cookies 登录
# 			# 3.1 判断是否点数不够登录
# 			if status == ConstantAccount.STATUS_ACCOUNT_NO_COUNT:
# 				# 直接登录下一个账号
# 				return self.login_channel_next(task_id, context, corp_code, _type, username)
#
# 			# 直接返回 当前有效 cookies
# 			return {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_OK,
# 					ConstantAccount.LOGIN_STATUS: ConstantAccount.LOGIN_STATUS_SUCCESS}
#
# def login_channel_next(self, task_id, context, corp_code, _type, username):
# 	# 获取下一个登录账号
# 	num = self.get_next_account(username, context)
# 	if num == 1:
# 		# 执行登录
# 		l_data = self.login_channel(task_id, context)
# 		# 判断登录结果
# 		if l_data.get(ConstantAccount.STATUS) == ConstantAccount.STATUS_ACCOUNT_ERROR:
# 			# l_data.get(ConstantAccount.STATUS_ACCOUNT_ERROR)登录失败，先标记当前账号有问题，然后继续执行登录(下一个账号)
# 			RedisUtils.addEventAccount(corp_code, _type, username, ConstantAccount.STATUS_ACCOUNT_ERROR)
# 			self.do_login(task_id, context)
# 		elif l_data.get(ConstantAccount.STATUS) == ConstantAccount.STATUS_ACCOUNT_OK:
# 			# 登录成功，直接返回
# 			RedisUtils.addEventAccount(corp_code, _type, username, ConstantAccount.STATUS_ACCOUNT_OK)
# 			l_data[ConstantAccount.LOGIN_STATUS] = ConstantAccount.LOGIN_STATUS_SUCCESS
# 			return l_data
# 		else:
# 			# 异常--登录失败，直接返回
# 			return {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_ERROR,
# 					ConstantAccount.LOGIN_STATUS: ConstantAccount.LOGIN_STATUS_EXCEPTION}
# 	else:
# 		# 无账号可用，直接结束任务
# 		return {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_ERROR,
# 				ConstantAccount.LOGIN_STATUS: ConstantAccount.LOGIN_STATUS_NO_ACCOUNT}
#
# def login_channel(self, task_id, context):
# 	data = {ConstantAccount.STATUS: ConstantAccount.STATUS_ACCOUNT_OK}
# 	proxy = LoginProxy()
# 	try:
# 		cookies = proxy.login(context)
# 		data[ConstantAccount.COOKIES] = cookies
# 	except VertifyException:
# 		TaskLogin.logger.info("登录任务 -- [%s] --执行登录, 验证码错误，任务结束..." % task_id)
# 		data[ConstantAccount.STATUS] = ConstantAccount.STATUS_VERIFY_ERROR
# 	except AccountException:
# 		TaskLogin.logger.info("登录任务 -- [%s] --执行登录, 账号密码错误, 重新其他账号登录 ..." % task_id)
# 		data[ConstantAccount.STATUS] = ConstantAccount.STATUS_ACCOUNT_ERROR
# 	return data
#
# def get_next_account(self, username, context):
# 	list_account = context[Constants.CONTEXT_ACCOUNT_LIST]
# 	index = 0
# 	for account in list_account:
# 		if username == account.get(Constants.CONTEXT_USERNAME):
# 			break
# 		index += 1
# 	# 获取下一个账户的坐标
# 	index += 1
# 	# 过滤数组越界
# 	if len(list_account) >= index:
# 		account = list_account[index]
# 		context[Constants.CONTEXT_USERNAME] = account.get(Constants.CONTEXT_USERNAME)
# 		context[Constants.CONTEXT_PASSWORD] = account.get(Constants.CONTEXT_PASSWORD)
# 		context[Constants.CONTEXT_ACCOUNT] = account.get(Constants.CONTEXT_ACCOUNT)
# 		return 1
# 	return 0
